import axios from 'axios'
import { useNotification } from './useNotification.js'
import { getAccessToken, getRefreshToken, setAccessToken, setRefreshToken, removeTokens } from './auth'
import { useConfirm } from './useConfirm'
import { logger } from './logger';

let internalConfig = {
  router: null,
  pinia: null, // <--- 新增 pinia 实例的存储位置
  auth: {
    enabled: false,
    loginRoute: '/login',
    refreshEndpoint: '/oauth/refresh',
  },
  errorRoutes: {
    401: '/login',
    403: '/403', // 新增：权限不足页面
    404: '/404',
    500: '/500', // 新增：服务器错误页面
  },
  // notificationHandler: null, // <--- 不再在这里固化
};

let isRefreshing = false;
let requestsToRetry = [];

const apiClient = axios.create({
  timeout: 10000,
})

export const initializeApiClient = (options = {}) => {
  logger.info('[initializeApiClient] 函数被调用，传入的 options:', options);
  internalConfig = {
    ...internalConfig,
    ...options,
    auth: { ...internalConfig.auth, ...options.auth },
    errorRoutes: { ...internalConfig.errorRoutes, ...options.errorRoutes },
    // notificationHandler: useNotification, // <--- 不再在这里固化
    pinia: options.pinia, // <--- 保存 pinia 实例
  };

  if (options.api && options.api.baseURL) {
    apiClient.defaults.baseURL = options.api.baseURL;
  }
  logger.info('[initializeApiClient] 配置完成，最终的 internalConfig:', internalConfig);
};

apiClient.interceptors.request.use(
  (req) => {
    logger.info('[Request Interceptor] 拦截到请求:', req.method.toUpperCase(), req.url);
    if (internalConfig.auth.enabled) {
      const accessToken = getAccessToken();
      if (accessToken) {
        req.headers.Authorization = `Bearer ${accessToken}`;
      }
    }
    return req;
  },
  (error) => {
    return Promise.reject(error);
  }
)

apiClient.interceptors.response.use(
  (response) => {
    const res = response.data;
    const originalRequest = response.config;

    // [重构] 根据业务码进行精细化处理
    switch (res.code) {
      case 200:
        // 业务成功，直接返回数据
        return Promise.resolve(res);
      
      case 400:
        // 业务错误，弹出通知并拒绝
        const errorMessage = res.message || '业务处理失败';
        const notification = useNotification(internalConfig.pinia);
        notification.error({ title: '操作失败', message: errorMessage });
        return Promise.reject(new Error(errorMessage));
        
      case 401:
        // 如果开启了认证，则触发 token 刷新流程
        if (internalConfig.auth.enabled) {
          logger.warn(`[Response Interceptor] 收到业务码 401，触发 Token 刷新流程。URL: ${originalRequest.url}`);
          // [修改] 使用新的 handle401Error，传入重试回调
          return handle401Error(() => apiClient(originalRequest));
        }
        // 如果未开启认证，则视为普通业务错误
        const authDisabledError = res.message || '用户认证失败（认证系统未启用）';
        const authNotification = useNotification(internalConfig.pinia);
        authNotification.error({ title: '认证错误', message: authDisabledError });
        return Promise.reject(new Error(authDisabledError));

      case 403:
        // 如果开启了认证，则跳转到 403 页面
        if (internalConfig.auth.enabled) {
            logger.warn(`[Response Interceptor] 收到业务码 403，跳转到无权限页面。`);
            if (internalConfig.router && internalConfig.errorRoutes[403]) {
                internalConfig.router.push(internalConfig.errorRoutes[403]);
            }
        }
        return Promise.reject(new Error(res.message || '权限不足'));
      
      case 500:
        // [修改] 不再跳转到 500 页面，而是弹出通知
        const serverErrorMessage = res.message || '服务器内部错误';
        const serverErrorNotification = useNotification(internalConfig.pinia);
        serverErrorNotification.error({ title: '服务器错误', message: serverErrorMessage });
        return Promise.reject(new Error(serverErrorMessage));

      default:
        // 其他未预期的 code，也视为错误
        const defaultErrorMessage = `未知的业务响应代码: ${res.code}`;
        const defaultNotification = useNotification(internalConfig.pinia);
        defaultNotification.error({ title: '未知错误', message: defaultErrorMessage });
        return Promise.reject(new Error(defaultErrorMessage));
    }
  },
  async (error) => {
    const originalRequest = error.config;

    // 如果没有 error.response，说明是网络错误等，直接交给通用处理器
    if (!error.response) {
      return handleGenericError(error);
    }
    
    // [重构] 如果是 HTTP 401 错误，且启用了 auth，则走刷新 token 逻辑
    // 排除掉刷新 token 本身的请求，避免死循环
    if (error.response.status === 401 && internalConfig.auth.enabled && !originalRequest.url.includes(internalConfig.auth.refreshEndpoint)) {
      logger.warn(`[Response Interceptor] 收到 HTTP 状态码 401，触发 Token 刷新流程。URL: ${originalRequest.url}`);
      // [修改] 使用新的 handle401Error，传入重试回调
      return handle401Error(() => apiClient(originalRequest));
    }

    // [最终清理] 对于其他 HTTP 错误，交给通用处理器
    logger.error('[Response Interceptor] 捕获到传输层错误:', error);
    return handleGenericError(error);
  }
)

function handleGenericError(error) {
    let message = '请求失败，请稍后重试';

    if (error.response) {
      const { status, data } = error.response;
      
      // [修复] 根据新规范，当发生特定 HTTP 错误时，应跳转到专用页面
      switch (status) {
        // 401 已被上层拦截器处理，这里不再需要
        case 403:
          if (internalConfig.auth.enabled) {
            if (internalConfig.router && internalConfig.errorRoutes[403]) {
              internalConfig.router.push(internalConfig.errorRoutes[403]);
            }
          }
          break;
        case 404:
          if (internalConfig.router && internalConfig.errorRoutes[404]) {
            internalConfig.router.push(internalConfig.errorRoutes[404]);
          }
          break;
        // [修改] 移除 case 500，让其落入 default 处理，弹出通知
        // case 500:
        //   if (internalConfig.auth.enabled) {
        //     if (internalConfig.router && internalConfig.errorRoutes[500]) {
        //       internalConfig.router.push(internalConfig.errorRoutes[500]);
        //     }
        //   }
        //   break;
        default:
          // 对于其他未配置页面跳转的错误，弹出通知
          const notification = useNotification(internalConfig.pinia);
          notification.error({ 
            title: `请求出错 (${status})`, 
            message: data?.message || error.message || '发生未知错误'
          });
          break;
      }

      // 统一解析 message，用于 Promise.reject
      message = data?.message || error.message || '发生未知错误';

    } else if (error.request) {
      const title = '网络错误';
      message = '网络连接异常，请检查网络设置';
      // 网络错误也需要弹出通知
      const notification = useNotification(internalConfig.pinia);
      notification.error({ title, message });
    } else {
      const title = '配置错误';
      message = `请求配置错误: ${error.message}`;
      // 配置错误也需要弹出通知
      const notification = useNotification(internalConfig.pinia);
      notification.error({ title, message });
    }
    
    // [最终修复] 始终抛出一个标准的 Error 对象，以统一所有错误路径，防止上层组件因接收到不同类型的错误对象而崩溃。
    return Promise.reject(new Error(message));
}

/**
 * [重构] 统一处理 401 错误，负责刷新 Token 或重定向到登录页。
 * @param {function(): Promise<any>} retryCallback - 一个函数，调用它会重试原始的请求。
 */
function handle401Error(retryCallback) {
  if (!isRefreshing) {
    isRefreshing = true;
    const refreshPromise = refreshToken();

    // 将重试逻辑绑定到刷新 promise 上
    refreshPromise.then(() => {
      logger.info(`[handle401Error] Token 刷新成功，重试 ${requestsToRetry.length} 个挂起的请求。`);
      requestsToRetry.forEach(cb => cb.resolve(cb.retry())); // 执行挂起的重试
      requestsToRetry = [];
    }).catch(() => {
      // 如果刷新失败，拒绝所有挂起的请求
      requestsToRetry.forEach(cb => cb.reject(new Error('Token refresh failed')));
      requestsToRetry = [];
    }).finally(() => {
      isRefreshing = false;
    });
    
    // 返回当前请求的重试 promise
    return refreshPromise.then(retryCallback).catch(err => {
      // 如果刷新失败，最终会在这里处理认证错误
      handleAuthError('会话已过期，请重新登录');
      return Promise.reject(err);
    });

  } else {
    // 如果正在刷新，则将当前请求的重试函数和 promise 的 resolve/reject 方法加入队列
    logger.info(`[handle401Error] 检测到正在刷新 Token，将请求加入队列。`);
    return new Promise((resolve, reject) => {
      requestsToRetry.push({
        retry: retryCallback,
        resolve: resolve,
        reject: reject
      });
    });
  }
}

/**
 * [重构] 调用刷新令牌的端点。现在它只负责刷新，不处理重试逻辑。
 */
async function refreshToken() {
  const rToken = getRefreshToken();
  if (!rToken) {
    logger.error('[refreshToken] 无法刷新：本地无 Refresh Token。');
    // [修改] 刷新失败时直接拒绝 Promise
    return Promise.reject(new Error('No refresh token available'));
  }

  logger.info('[refreshToken] 开始尝试刷新 Access Token...');
  try {
    // 使用一个不带拦截器的纯净 axios 实例来发送刷新请求，避免循环
    const response = await axios.post(
      internalConfig.auth.refreshEndpoint, 
      { refresh_token: rToken },
      { baseURL: apiClient.defaults.baseURL }
    );
    
    const tokenData = response.data.data || response.data;
    const { access_token: newAccessToken, refresh_token: newRefreshToken } = tokenData;

    if (!newAccessToken) {
      throw new Error('Invalid new access token received from refresh endpoint');
    }

    setAccessToken(newAccessToken);
    if (newRefreshToken) {
      setRefreshToken(newRefreshToken);
    }
    
    logger.info('[refreshToken] Access Token 刷新成功!');
    return newAccessToken;
  } catch (error) {
    logger.error('[refreshToken] 刷新 Access Token 彻底失败:', error);
    // [修改] 刷新失败时，调用 handleAuthError 并拒绝 promise
    handleAuthError('会话已过期，请重新登录');
    return Promise.reject(error); 
  }
}

function handleAuthError(message) {
  logger.info('--- handleAuthError 函数被调用 ---');
  logger.error(`[handleAuthError] 认证彻底失败: ${message}。准备强制跳转到登录页...`);
  removeTokens();
  
  if (internalConfig.router) {
    logger.info('[handleAuthError] Router 实例存在，执行跳转...');
    internalConfig.router.push(internalConfig.auth.loginRoute);
  } else {
    logger.error('[handleAuthError] 无法跳转！internalConfig.router 未定义！');
  }
  
  // 返回一个永远挂起的 Promise，以中断错误传播链，防止在控制台打印错误
  return new Promise(() => {});
}

/**
 * [新增] 发起流式 POST 请求 (用于 SSE)
 * 这个方法不经过标准的响应拦截器，因为它需要直接处理原始的数据流。
 * @param {string} url - 请求的 URL
 * @param {object} data - 请求体数据
 * @param {function(string): void} onDataString - 接收到原始事件数据字符串时的回调函数
 * @param {AbortSignal} signal - 用于中止请求的 AbortSignal
 * @returns {Promise<void>}
 */
apiClient.postStream = async function(url, data, onDataString, signal, isRetry = false) {
  try {
    const headers = {
      'Content-Type': 'application/json',
      'Accept': 'text/event-stream',
    };
    
    // 复用请求拦截器中的逻辑，在 auth.enabled 为 true 时才添加 token
    if (internalConfig.auth.enabled) {
      const token = getAccessToken();
      if (token) {
        headers['Authorization'] = `Bearer ${token}`;
      }
    }

    const fullUrl = `${apiClient.defaults.baseURL || ''}${url}`;

    const response = await fetch(fullUrl, {
      method: 'POST',
      headers: headers,
      body: JSON.stringify(data),
      signal: signal,
    });

    if (!response.ok) {
        // [新增] 专门处理 401 错误，并与通用刷新逻辑集成
        if (response.status === 401 && internalConfig.auth.enabled && !isRetry) {
          logger.warn('[postStream] 流式请求收到 401，触发 Token 刷新流程。');
          // 将重试自身的逻辑作为回调传递给 handle401Error
          return handle401Error(() => apiClient.postStream(url, data, onDataString, signal, true));
        }

        const errorBody = await response.json().catch(() => null);
        const errorMessage = errorBody?.message || `请求失败，状态码: ${response.status}`;
        throw new Error(errorMessage);
    }
    
    // [重构] 使用浏览器原生的 ReadableStream API 处理 SSE
    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let buffer = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        break; // 读取完毕
      }
      
      buffer += decoder.decode(value, { stream: true });
      
      // SSE 事件以 `\n\n` 分隔
      const lines = buffer.split('\n\n');
      buffer = lines.pop(); // 保留最后一行（可能不完整）

      for (const line of lines) {
        if (line.startsWith('data: ')) {
          const eventData = line.substring(6).trim();
          if (eventData === '[DONE]') {
            return; // 后端发来结束信号
          }
          try {
            // [重构] 不再解析JSON，直接将原始数据字符串通过回调传出
            onDataString(eventData);
          } catch (e) {
            // 这个 catch 块现在不太可能被触发，除非 onDataString 本身有异常
            logger.error('流式数据回调函数执行出错:', e);
          }
        }
      }
    }

  } catch (error) {
    if (error.name === 'AbortError') {
      logger.info('流式请求被用户取消。');
    } else {
      logger.error('流式连接失败:', error);
      // 手动触发通知
      const notification = useNotification(internalConfig.pinia);
      notification.error({
        title: '流式连接失败',
        message: error.message || '无法建立连接，请检查网络或联系管理员。'
      });
    }
    // 将错误向上抛出，以便调用方可以捕获它
    throw error;
  }
};

export default apiClient